﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Diagnostics;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.WebControls;
using Microsoft.IdentityModel;
using Microsoft.IdentityModel.Claims;
using Microsoft.Office.Server;
using Microsoft.Office.Server.Audience;

namespace WingtipClaimProviders {
  class AudienceClaimProvider : SPClaimProvider {

    public AudienceClaimProvider(string displayName)
      : base(displayName) {
    }

    internal const string ClaimProviderDisplayName = "Audience Claim Provider";
    internal const string ClaimProviderDescription = "SharePoint 2010 Demoware from Critical Path Training";
    // this is the only claim type supported by this provider
    protected const string AudienceClaimType = "http://www.wingtip.com/identity/claims/audience";
    protected const string StringTypeClaim = Microsoft.IdentityModel.Claims.ClaimValueTypes.String;

    protected static string CentralAdminUrl {
      get { return SPAdministrationWebApplication.Local.AlternateUrls[0].IncomingUrl; }
    }


    public override string Name {
      get { return ClaimProviderDisplayName; }
    }

    public override bool SupportsEntityInformation {
      get { return true; }
    }

    public override bool SupportsHierarchy {
      get { return true; }
    }

    public override bool SupportsResolve {
      get { return true; }
    }

    public override bool SupportsSearch {
      get { return true; }
    }

    protected override void FillClaimTypes(List<string> claimTypes) {
      if (claimTypes == null) throw new ArgumentException("claimTypes");

      claimTypes.Add(AudienceClaimType);
    }

    protected override void FillClaimValueTypes(List<string> claimValueTypes) {
      if (claimValueTypes == null) throw new ArgumentException("claimValueTypes");

      claimValueTypes.Add(StringTypeClaim);
    }

    protected override void FillEntityTypes(List<string> entityTypes) {
      entityTypes.Add(SPClaimEntityTypes.FormsRole);
    }

    protected override void FillClaimsForEntity(System.Uri context, SPClaim entity, List<SPClaim> claims) {
      if (entity == null) throw new ArgumentException("entity");
      if (claims == null) throw new ArgumentException("claims");


      // determine whether current user is in any audiences
      using (SPSite siteCollection = new SPSite(CentralAdminUrl)) {
        SPServiceContext ctx = SPServiceContext.GetContext(siteCollection);
        AudienceManager mgr = new AudienceManager(ctx);
        foreach (Audience audience in mgr.Audiences) {
          // capture user login name 
          string userLogin = entity.Value;
          // Strip off claims prefix from user login
          if (userLogin.StartsWith("0#.w|")) {
            userLogin = userLogin.Substring(5);
          }
          if (audience.IsMember(userLogin)) {
            // if so, create a new claim and add it to SAML token of current user
            claims.Add(CreateClaim(AudienceClaimType, audience.AudienceName, StringTypeClaim));
          }
        }
      }
    }


    protected override void FillHierarchy(System.Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, SPProviderHierarchyTree hierarchy) {
      // No additional nodes need to be added to the People Picker
    }


    protected override void FillSearch(System.Uri context, string[] entityTypes, string searchPattern, string hierarchyNodeID, int maxCount, SPProviderHierarchyTree searchTree) {
      if (EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole)) {
        List<string> audiences = new List<string>();
        // get SPSite object for Central Admin
        using (SPSite ca = new SPSite(CentralAdminUrl)) {
          // Get SharePoint Server 2010 Audience Manager
          SPServiceContext ctx = SPServiceContext.GetContext(ca);
          AudienceManager mgr = new AudienceManager(ctx);
          // determine if search string matches any audience names
          foreach (Audience audience in mgr.Audiences) {
            if (audience.AudienceName.StartsWith(searchPattern, StringComparison.CurrentCultureIgnoreCase))
              // add any audiences that match search string
              audiences.Add(audience.AudienceName);
          }
        }
        // Add picker entity for each audience that matches
        foreach (string audienceName in audiences)
          searchTree.AddEntity(CreatePickerEntityForAudience(audienceName));
      }
    }

    protected override void FillSchema(SPProviderSchema schema) {
      // add schema element for display name
      schema.AddSchemaElement(new SPSchemaElement(
                                  PeopleEditorEntityDataKeys.DisplayName,
                                  "Display Name",
                                  SPSchemaElementType.Both));
    }

    private PickerEntity CreatePickerEntityForAudience(string audience) {
      //Create and initialize new Picker Entity
      PickerEntity entity = CreatePickerEntity();
      entity.Claim = CreateClaim(AudienceClaimType, audience, StringTypeClaim);
      entity.Description = ClaimProviderDisplayName + ":" + audience;
      entity.DisplayText = audience;
      entity.EntityType = SPClaimEntityTypes.FormsRole;
      entity.IsResolved = true;
      entity.EntityGroupName = "Wingtip Audience";
      entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = audience;
      return entity;
    }


    protected override void FillResolve(System.Uri context, string[] entityTypes, SPClaim resolveInput, List<PickerEntity> resolved) {
      if (resolveInput.ClaimType == (AudienceClaimType))
        resolved.Add(CreatePickerEntityForAudience(resolveInput.Value));
    }

    protected override void FillResolve(System.Uri context, string[] entityTypes, string resolveInput, List<PickerEntity> resolved) {

      List<string> audiences = new List<string>();

      using (SPSite ca = new SPSite(CentralAdminUrl)) {
        SPServiceContext ctx = SPServiceContext.GetContext(ca);
        AudienceManager mgr = new AudienceManager(ctx);

        foreach (Audience audience in mgr.Audiences) {
          if (audience.AudienceName.StartsWith(resolveInput, StringComparison.CurrentCultureIgnoreCase))
            audiences.Add(audience.AudienceName);
        }
      }

      foreach (string audienceName in audiences) {
        resolved.Add(CreatePickerEntityForAudience(audienceName));
      }
    }
  }
}
